pub trait Op {
    fn name(&self) -> &'static str;
    fn exec(&self, a: f32, b: f32) -> Option<f32>;
    fn is_primary(&self) -> bool;
}

pub struct Add;
pub struct Sub;
pub struct Mul;
pub struct Div;

impl Op for Add {
    fn name(&self) -> &'static str {
        "+"
    }

    fn exec(&self, a: f32, b: f32) -> Option<f32> {
        Some(a + b)
    }

    fn is_primary(&self) -> bool {
        false
    }
}

impl Op for Sub {
    fn name(&self) -> &'static str {
        "-"
    }

    fn exec(&self, a: f32, b: f32) -> Option<f32> {
        Some(a - b)
    }

    fn is_primary(&self) -> bool {
        false
    }
}

impl Op for Mul {
    fn name(&self) -> &'static str {
        "*"
    }

    fn exec(&self, a: f32, b: f32) -> Option<f32> {
        Some(a * b)
    }

    fn is_primary(&self) -> bool {
        true
    }
}

impl Op for Div {
    fn name(&self) -> &'static str {
        "/"
    }

    fn exec(&self, a: f32, b: f32) -> Option<f32> {
        if b == 0.0 {
            return None;
        }
        Some(a / b)
    }

    fn is_primary(&self) -> bool {
        true
    }
}

pub type F32Op = Box<dyn Op>;
